package com.qingyun.ipc

import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import com.qingyun.ipc.impl.ComputeImpl
import com.qingyun.ipc.impl.SecurityCenterImpl
import java.util.concurrent.CountDownLatch

class BinderPool private constructor(context: Context) {

    companion object {
        private const val BINDER_NONE = -1
        private const val BINDER_COMPUTE = 0
        private const val BINDER_SECURITY_CENTER = 1

        @SuppressLint("StaticFieldLeak")
        @Volatile
        private var instance: BinderPool? = null

        @JvmStatic
        fun getInstance(context: Context): BinderPool {
            return instance ?: synchronized(this) {
                instance ?: BinderPool(context.applicationContext).also {
                    instance = it
                }
            }
        }
    }

    private val mContext: Context = context
    private var mCountdownLatch: CountDownLatch? = null
    private var mBinderPool: IBinderPool? = null

    private val conn = object : ServiceConnection {
        override fun onServiceConnected(
            name: ComponentName?,
            service: IBinder?,
        ) {
            mBinderPool = IBinderPool.Stub.asInterface(service)
            mBinderPool?.asBinder()?.linkToDeath(mBinderPoolDeathRecipient, 0)
            mCountdownLatch?.countDown()
        }

        override fun onServiceDisconnected(name: ComponentName?) {

        }
    }
    private val mBinderPoolDeathRecipient = object : IBinder.DeathRecipient {
        override fun binderDied() {
            mBinderPool?.asBinder()?.unlinkToDeath(this, 0)
            mBinderPool = null
            connectBinderPoolService()
        }

    }

    private fun connectBinderPoolService() {
        mCountdownLatch = CountDownLatch(1)
        val intent = Intent(mContext, BinderPoolService::class.java)
        mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)
        mCountdownLatch!!.await()
    }

    private fun queryBinder(binderCode: Int): IBinder? {
        return mBinderPool?.queryBinder(binderCode)
    }

    class BinderPoolImpl : IBinderPool.Stub() {
        override fun queryBinder(binderCode: Int): IBinder? {
            return when (binderCode) {
                BINDER_SECURITY_CENTER -> SecurityCenterImpl()
                BINDER_COMPUTE -> ComputeImpl()
                else -> null
            }
        }
    }
}